﻿using Engine;
using GameEntitySystem;
using System;
using System.Collections.Generic;

namespace Game
{
    /// <summary>
    /// 命令方块数据
    /// </summary>
    public class CommandData
    {
        public Point3 Position;
        public string Line;
        public string Name;
        public string Type = "default";
        public WorkingMode Mode = WorkingMode.Default;
        public CoordinateMode Coordinate = CoordinateMode.Default;
        public Dictionary<string, object> Data = new Dictionary<string, object>();
        public Dictionary<string, string> DataText = new Dictionary<string, string>();
        public bool OutRange = false;
        public bool Valid = true;
        public Dictionary<string, object> DIYPara = new Dictionary<string, object>();

        public CommandData(Point3 position, string line)
        {
            Position = position;
            Line = line;
        }

        public object GetValue(string key)
        {
            if (Data.TryGetValue(key, out object value))
            {
                return value;
            }
            return null;
        }

        public string TrySetValue()
        {
            if (Line == "" || string.IsNullOrEmpty(Line))
            {
                Valid = false;
                return string.Empty;
            }
            try
            {
                Line = Line.Replace("\n", " ");
                string[] words = Line.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (!words[0].Contains(":")) words[0] = "cmd:" + words[0];
                string[] firstWord = words[0].Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
                Name = firstWord[1];
                Mode = WorkingMode.Default;
                if (firstWord[0].ToLower() == "if")
                {
                    Mode = WorkingMode.Condition;
                }
                else
                {
                    if (DataHandle.IsContainsVariable(Line))
                    {
                        Mode = WorkingMode.Variable;
                    }
                }
                for (int i = 0; i < words.Length; i++)
                {
                    if (!words[i].Contains(":") && words[i].Contains("@")) words[i] = "cd:" + words[i];
                    string[] keyValue = words[i].Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
                    string key = keyValue[0].ToLower();
                    switch (key)
                    {
                        case "type": Type = InstructionManager.GetCommandType(Name, (Mode == WorkingMode.Condition), keyValue[1].ToLower()); break;
                        case "cd":
                            {
                                if (keyValue[1].ToLower() == "@c") Coordinate = CoordinateMode.Command;
                                else if (keyValue[1].ToLower() == "@pl") Coordinate = CoordinateMode.Player;
                                break;
                            }
                        default: break;
                    }
                    if (!InstructionManager.IsFixedParameter(key))
                    {
                        DataText[key] = keyValue[1];
                    }
                }
                foreach (string word in words)
                {
                    string[] keyValue = word.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
                    if (Mode == WorkingMode.Variable)
                    {
                        if (DataHandle.IsContainsVariable(keyValue[0] + ":" + keyValue[1]))
                        {
                            Data[keyValue[0]] = keyValue[1];
                            continue;
                        }
                    }
                    SetDataPara(keyValue[0].ToLower(), keyValue[1]);
                }
                if (Mode != WorkingMode.Variable)
                {
                    Instruction instruction = InstructionManager.GetInstruction(Name, Mode == WorkingMode.Condition);
                    if (instruction != null)
                    {
                        foreach (string key in Data.Keys)
                        {
                            if (instruction.Ranges.TryGetValue(Type + "$" + key, out Point2 range))
                            {
                                int dataValue = (int)Data[key];
                                if (!(dataValue >= range.X && dataValue <= range.Y))
                                {
                                    OutRange = true;
                                    string p = InstructionManager.GetParameterName(Name, Type, key, Mode == WorkingMode.Condition);
                                    return string.Format("{0}指令的{1}(类型:{2})的参数范围为{3}-{4}，请纠正数值", Name, p, Type, range.X, range.Y);
                                }
                            }
                        }
                    }
                    else
                    {
                        Valid = false;
                        return "当前编辑的指令是无效的，请重新编辑";
                    }
                }
                Valid = true;
                return string.Empty;
            }
            catch
            {
                Valid = false;
                if (Mode == WorkingMode.Condition && DataHandle.IsContainsVariable(Line))
                {
                    return "条件判断模式不支持指令变量";
                }
                return "当前编辑的指令是无效的，请重新编辑";
            }
        }

        public void FastSetValue()
        {
            foreach (var varKey in DataText.Keys)
            {
                if (!DataHandle.IsContainsVariable(varKey + ":" + DataText[varKey])) continue;
                try
                {
                    SetDataPara(varKey.ToLower(), Data[varKey].ToString());
                }
                catch
                {
                }
            }
        }

        public void SetDataPara(string key, string value)
        {
            switch (key)
            {
                case "cmd": break;
                case "if": break;
                case "type": break;
                case "cd": break;
                case "vec2": Data[key] = DataHandle.GetVector2Value(value); break;
                case "vec3": Data[key] = DataHandle.GetVector3Value(value); break;
                case "vec4": Data[key] = DataHandle.GetVector4Value(value); break;
                default:
                    {
                        if (key.StartsWith("id")) Data[key] = DataHandle.GetNaturalValue(value);
                        else if (key.StartsWith("fid")) Data[key] = DataHandle.GetNaturalValue(value);
                        else if (key.StartsWith("pos")) Data[key] = DataHandle.GetPoint3Value(value);
                        else if (key.StartsWith("eyes")) Data[key] = DataHandle.GetPoint2Value(value);
                        else if (key.StartsWith("con")) Data[key] = DataHandle.GetBoolValue(value);
                        else if (key.StartsWith("color")) Data[key] = DataHandle.GetColorValue(value);
                        else if (key.StartsWith("text")) Data[key] = DataHandle.CharacterEscape(value);
                        else if (key.StartsWith("obj")) Data[key] = value.ToLower();
                        else if (key.StartsWith("time")) Data[key] = DataHandle.GetDateTimeValue(value);
                        else if (key.StartsWith("fix")) Data[key] = DataHandle.CharacterEscape(value);
                        else if (key.StartsWith("opt")) Data[key] = DataHandle.CharacterEscape(value);
                        else if (int.TryParse(value, out int num)) Data[key] = num;
                        else Data[key] = value;
                    }
                    break;
            }
        }
    }
}